﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using GuidanceExplorer;
using GuidanceExplorer.Controls;
using GuidanceExplorer.Model;
using GuidanceExplorer.Services;
using GuidanceExplorer.Views;
using GuidanceExplorerAddIn.Services;
using GuidanceExplorerAddIn.Windows;

namespace GuidanceExplorerAddIn.Controls
{

    public partial class GETreeView : UserControl
    {
        struct DragDropOperation
        {
            public object Item;
            public object From;
            public TreeNode To;
            public int PreviousPosition;
		}

		#region Members

		private GEWindow tool;
        private bool afterEditMessageShown = false;
		//private IModelStorageService _modelService;
        private TreeNode _oldNode;
        private Stack<DragDropOperation> _operations;
        private TreeNode _lastSelectedNode;
		private bool _mouseDown = false;
        private bool _onlyClick = false;

		#endregion


		#region Events

		public event EventHandler<ModelNodeEventArgs<UserViews>> MyViewsSelected;
        public event EventHandler<ModelNodeEventArgs<GuidanceExplorer.Model.Checklist>> ChecklistNodeSelected;
        public event EventHandler<EventArgs> LibrariesNodeSelected;
        public event EventHandler<ModelNodeEventArgs<Library>> LibraryNodeSelected;
        public event EventHandler<ModelNodeEventArgs<Library>> LibraryNodeDeleted;
        public event EventHandler<ModelNodeEventArgs<GuidanceExplorer.Model.View>> ViewNodeSelected;
        public event EventHandler<ModelNodeEventArgs<SearchView>> SearchViewNodeSelected;
        public event EventHandler<ModelNodeEventArgs<GuidanceExplorer.Model.View>> ViewNodeDeleted;
        public event EventHandler<ModelNodeEventArgs<SearchView>> SearchViewNodeDeleted;
        public event EventHandler<ModelNodeEventArgs<Folder>> FolderNodeSelected;
        public event EventHandler<ModelNodeEventArgs<Folder>> FolderNodeDeleted;
        public event EventHandler<ModelNodeEventArgs<GuidanceType>> GuidanceTypeNodeSelected;
        //public event EventHandler<ModelNodeEventArgs<GuidanceItemFileReference>> GuidanceItemNodeSelected;
        public event EventHandler<GuidanceItemFileReferenceEventArgs> GuidanceItemNodeSelected;

        public event EventHandler<EventArgs> AuthoringToolkitNodeSelected;
        public event EventHandler<DropOperationEventArgs<GuidanceExplorer.Model.View, Library>> DropViewToLibrary;
        public event EventHandler<DropOperationEventArgs<GuidanceExplorer.Model.View, UserViews>> DropViewToUserViews;
        public event EventHandler<DropOperationEventArgs<GuidanceExplorer.Model.View, Folder>> DropViewToFolder;
        public event EventHandler<DropOperationEventArgs<SearchView, Library>> DropSearchViewToLibrary;
        public event EventHandler<DropOperationEventArgs<SearchView, UserViews>> DropSearchViewToUserViews;
        public event EventHandler<DropOperationEventArgs<SearchView, Folder>> DropSearchViewToFolder;
        public event EventHandler<DropOperationEventArgs<Folder, Library>> DropFolderToLibrary;
        public event EventHandler<DropOperationEventArgs<Folder, UserViews>> DropFolderToUserViews;
        public event EventHandler<DropOperationEventArgs<Folder, Folder>> DropFolderToFolder;
		public event EventHandler<CancelEventArgs> OpeningContextMenuTreeView;
		//public event EventHandler<ItemAddToFolderEventArgs> ItemAddToFolder;
        public event EventHandler<ItemDropOperationEventArgs<GuidanceItemFileReference, GuidanceExplorer.Model.View>> DropItemToView;
        public event EventHandler<ItemDropOperationEventArgs<GuidanceItemFileReference, Checklist>> DropItemToChecklist;
		public event EventHandler<DropOperationEventArgs<Checklist, Folder>> DropCheckListToFolder;
		public event EventHandler<DropOperationEventArgs<Folder, SolutionViews>> DropFolderToSolutionNode;
		public event EventHandler<DropOperationEventArgs<Checklist, SolutionViews>> DropCheckListToSolutionNode;
		public event EventHandler<DropOperationEventArgs<GuidanceExplorer.Model.View, SolutionViews>> DropViewToSolutionNode;
		public event EventHandler<DropOperationEventArgs<GuidanceExplorer.Model.View,Checklist>> DropViewToChecklist;
		public event EventHandler<DropOperationEventArgs<Folder, Checklist>> DropFolderToCheckList;
		public event EventHandler<DropOperationEventArgs<SearchView, Checklist>> DropSearchViewToCheckList;
		public event EventHandler<DropOperationEventArgs<GuidanceExplorer.Model.View, GuidanceExplorer.Model.View>> DropViewToView;
		public event EventHandler<DropOperationEventArgs<SearchView, GuidanceExplorer.Model.View>> DropSearchViewToView;
		public event EventHandler<DropOperationEventArgs<Folder, GuidanceExplorer.Model.View>> DropFolderToView;


        #endregion

        /// <summary>
        /// The TreeView instance for this control.
        /// </summary>
        public TreeView TreeView
        {
            get { return this.treeView; }
        }
        
        //public IModelStorageService ModelService
        //{
        //    set { _modelService = value; }
        //}

        public IAddinModelStorageService ModelService { private get; set; }
        //bool NewGuidanceAdded { get; set; }
        
        
        string CurrentAddInPath
        {
            get
            {
                return Path.GetDirectoryName(this.GetType().Assembly.Location);
            }
        }

        public GETreeView(GEWindow tool)
        {
            InitializeComponent();
            this.tool = tool;
            _oldNode = null;
            _operations = new Stack<DragDropOperation>();
        }

        /// <summary>
        /// Return the node currently selected.
        /// </summary>
        public TreeNode LastSelectedNode
        {
            get
            {
                //return treeView.SelectedNode;
                //return _selectedNodes[_selectedNodes.Count - 1];
                return _lastSelectedNode;
            }
        }

        /// <summary>
        /// Return the node currently selected.
        /// </summary>
        /// <returns></returns>
        public TreeNode GetCurrentNode()
        {
            return _lastSelectedNode;// treeView.SelectedNode;
        }

        public void Init()
        {
            //TODO: review.
            //GuidanceExplorer.Services.AsyncLoadLibrariesService asyncLoadSLibraryService = new GuidanceExplorer.Services.AsyncLoadLibrariesService();
            //asyncLoadSLibraryService.ProcessGuidance(ModelService.Guidance, null);

            WinFormsRenderService winFormsRenderService = new WinFormsRenderService();
            winFormsRenderService.RenderGuidanceToTreeView(ModelService.Guidance, this.treeView);
           // NewGuidanceAdded = true;
        }
 

        /// <summary>
        /// Occurs when the Label is about to be edited.
        /// </summary>
        private void treeView_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            IModelItem modelNode = e.Node as IModelItem;
            //Only Model nodes are editable.
            e.CancelEdit = !new ModelItemMenuItemIsEditableCondition().ShowMenuItem(null, modelNode);
            if (e.CancelEdit)
            {
                return;
            }
			if (e.Node is GuidanceItemNode)
			{
				e.CancelEdit = true;
			}
            else if (modelNode != null)
            {
                if (!(modelNode is LibraryNode))
                {
                    //Cancel if the node is not editable.
                    e.CancelEdit = !modelNode.IsEditable;
                }
            }
            else
            {
                //Allow editing the create view node.
                CreateViewNode createViewNode = e.Node as CreateViewNode;
                if (createViewNode != null)
                {
                    e.CancelEdit = false;
                }
                else
                {
                    e.CancelEdit = true;
                }
            }
        }

        /// <summary>
        /// Occurs when the node has finished the edition mode.
        /// </summary>
        private void treeView_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            //Seems a bug in WinForms :)
            string newLabel = e.Label ?? e.Node.Text;

            //Check if the name exists
            TreeNodeCollection parentCollection = e.Node.Parent == null ? e.Node.TreeView.Nodes : e.Node.Parent.Nodes;

            foreach (TreeNode node in parentCollection)
            {
                if (node != e.Node && node.Text == newLabel)
                {
                    if (!afterEditMessageShown)
                    {
                        MessageBox.Show(Messages.NODE_NAME_EXISTS, Messages.ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    e.CancelEdit = true;
                    e.Node.BeginEdit();
                    afterEditMessageShown = false;
                    return;
                }
            }

            afterEditMessageShown = false;

            IModelItem modelNode = e.Node as IModelItem;
            //Only Model nodes are editable.
            if (modelNode != null)
            {
                LibraryNode libraryNode = modelNode as LibraryNode;
                ViewNode viewNode = modelNode as ViewNode;
                SearchViewNode searchViewNode = modelNode as SearchViewNode;
                FolderNode folderNode = modelNode as FolderNode;
                ChecklistNode checklistNode = modelNode as ChecklistNode;
                if (libraryNode != null)
                {
                    libraryNode.ModelInstance.Caption = newLabel;

                    libraryNode.ModelInstance.HasChanges = true;
                    //update the store immediately for library rename
                    //if (libraryNode.ModelInstance.WebSubscribed)
                    //{
                    //    OnlineStorageService onlineStorageService = new OnlineStorageService();
                    //    onlineStorageService.CreateLibrary(libraryNode.ModelInstance, true);
                    //}
                }
                else if (viewNode != null)
                {
                    if (viewNode.ModelInstance.Container != null)
                    {
                        viewNode.ModelInstance.Container.Views.Remove(viewNode.ModelInstance.Caption);
                        viewNode.ModelInstance.Caption = newLabel;
                        viewNode.ModelInstance.LastUpdate = DateTime.UtcNow; 
                        viewNode.ModelInstance.Container.Views.Add(newLabel, viewNode.ModelInstance);
                    }
                    else
                    {
                        viewNode.ModelInstance.ParentFolder.Views.Remove(viewNode.ModelInstance.Caption);
                        viewNode.ModelInstance.Caption = newLabel;
                        viewNode.ModelInstance.LastUpdate = DateTime.UtcNow;
                        viewNode.ModelInstance.ParentFolder.Views.Add(newLabel, viewNode.ModelInstance);
                    }
                    if (viewNode.ModelInstance.GetContainerLibrary() != null)
                    {
                        viewNode.ModelInstance.GetContainerLibrary().HasChanges = true;
                    }
                }
                else if (searchViewNode != null)
                {
                    if (searchViewNode.ModelInstance.Container != null)
                    {
                        searchViewNode.ModelInstance.Container.Views.Remove(searchViewNode.ModelInstance.Caption);
                        searchViewNode.ModelInstance.Caption = newLabel;
                        searchViewNode.ModelInstance.LastUpdate = DateTime.UtcNow;
                        searchViewNode.ModelInstance.Container.Views.Add(newLabel, searchViewNode.ModelInstance);
                    }
                    else
                    {
                        searchViewNode.ModelInstance.ParentFolder.Views.Remove(searchViewNode.ModelInstance.Caption);
                        searchViewNode.ModelInstance.Caption = newLabel;
                        searchViewNode.ModelInstance.LastUpdate = DateTime.UtcNow;
                        searchViewNode.ModelInstance.ParentFolder.Views.Add(newLabel, searchViewNode.ModelInstance);
                    }

                    if (searchViewNode.ModelInstance.GetContainerLibrary() != null)
                    {
                        searchViewNode.ModelInstance.GetContainerLibrary().HasChanges = true;
                    }
                }
                else if (folderNode != null)
                {
                    if (folderNode.ModelInstance.Container != null)
                    {
                        folderNode.ModelInstance.Container.Folders.Remove(folderNode.ModelInstance.Caption);
                        folderNode.ModelInstance.Caption = newLabel;
                        folderNode.ModelInstance.UpdateDateTime();
                        folderNode.ModelInstance.Container.Folders.Add(newLabel, folderNode.ModelInstance);
                    }
                    else
                    {
                        folderNode.ModelInstance.ParentFolder.Folders.Remove(folderNode.ModelInstance.Caption);
                        folderNode.ModelInstance.Caption = newLabel;
                        folderNode.ModelInstance.UpdateDateTime();
                        folderNode.ModelInstance.ParentFolder.Folders.Add(newLabel, folderNode.ModelInstance);
                    }
                    if (folderNode.ModelInstance.GetContainerLibrary() != null)
                    {
                        folderNode.ModelInstance.GetContainerLibrary().HasChanges = true;
                    }
                }
                else if (checklistNode != null)
                {
                    if (checklistNode.ModelInstance.Container != null)
                    {
                        checklistNode.ModelInstance.Container.Checklists.Remove(checklistNode.ModelInstance.Caption);
                        checklistNode.ModelInstance.Caption = newLabel;
                        checklistNode.ModelInstance.LastUpdate = DateTime.UtcNow;
                        checklistNode.ModelInstance.Container.Checklists.Add(newLabel, checklistNode.ModelInstance);
                    }
                    else
                    {
                        checklistNode.ModelInstance.ParentFolder.Checklists.Remove(checklistNode.ModelInstance.Caption);
                        checklistNode.ModelInstance.Caption = newLabel;
                        checklistNode.ModelInstance.LastUpdate = DateTime.UtcNow;
                        checklistNode.ModelInstance.ParentFolder.Checklists.Add(newLabel, checklistNode.ModelInstance);
                    }
                }
                
                e.CancelEdit = false;
            }
            else
            {
                //It's a not model node.
                CreateViewNode createViewNode = e.Node as CreateViewNode;
                if (createViewNode != null)
                {
                    //The Create View node can be edited, for creating new views.

                    //Update the model.
                    GuidanceExplorer.Model.View newView = GuidanceExplorer.Model.View.New();
                    newView.Caption = e.Label;
                    newView.Author = Environment.UserName;
                    newView.Container = ModelService.Guidance.UserViews;
                    newView.LastUpdate = DateTime.Today;

                    //Add the view to the UserViews.
                    ModelService.Guidance.UserViews.Views.Add(newView.Caption, newView);

                    //Update the TreeView.
                    MyViewsNode myViewsNode = createViewNode.Parent as MyViewsNode;
                    if (myViewsNode != null)
                    {
                        ViewNode viewNode = ViewNode.New();
                        viewNode.ModelInstance = newView;
                        viewNode.Text = newView.Caption;
                        myViewsNode.Nodes.Add(viewNode);

                        treeView.SelectedNode = viewNode;
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }

                    //It's cancelled but a new node has been created.
                    e.CancelEdit = true;
                }
                else
                {
                    e.CancelEdit = true;
                }
            }
        }

        /// <summary>
        /// Occurs when a key is pressed.
        /// </summary>
        private void treeView_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F2)
            {
                if (treeView.SelectedNode != null && treeView.LabelEdit)
                {
                    treeView.SelectedNode.BeginEdit();
                }
            }
            else if (e.KeyCode == Keys.Delete)
            {
                if (treeView.SelectedNode is MyViewsNode)
                {
                    //Do nothing
                }
                else if (treeView.SelectedNode is LibrariesNode)
                {
                    //Do nothing
                }
                else if (treeView.SelectedNode is LibraryNode)
                {
                    if (LibraryNodeDeleted != null)
                    {
                        LibraryNode libraryNode = treeView.SelectedNode as LibraryNode;

                        if (libraryNode != null)
                        {
                            if (libraryNode.ModelInstance.ReadProtection == ReadProtection.ReadOnly)
                            {
                                MessageBox.Show("Read-only Libraries can't be deleted", Messages.ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                            }
                            else if (MessageBox.Show(Messages.LIBRARY_DELETION_CONFIRMATION, Messages.WARNING,
                                MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                            {
                                LibraryNodeDeleted(this, new ModelNodeEventArgs<Library>(libraryNode));
                            }
                        }
                    }
                }
                else if (treeView.SelectedNode is FolderNode)
                {
                    if (FolderNodeDeleted != null)
                    {
                        FolderNode folderNode = treeView.SelectedNode as FolderNode;
                        Library containingLibrary = folderNode != null ? folderNode.ModelInstance.GetContainerLibrary() : null;

                        if (containingLibrary != null && containingLibrary.ReadProtection == ReadProtection.ReadOnly)
                        {
                            MessageBox.Show(Messages.CANNOT_DELETE_NODES_FROM_READ_ONLY_LIBRARIES, Messages.ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                        else if (MessageBox.Show(Messages.FOLDER_DELETION_CONFIRMATION, Messages.WARNING,
                            MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                        {
                            FolderNodeDeleted(this, new ModelNodeEventArgs<Folder>(folderNode));
                        }
                    }
                }
                else if (treeView.SelectedNode is ViewNode)
                {
                    if (ViewNodeDeleted != null)
                    {
                        ViewNode viewNode = treeView.SelectedNode as ViewNode;
                        Library containingLibrary = viewNode != null ? viewNode.ModelInstance.GetContainerLibrary() : null;

                        if (containingLibrary != null && containingLibrary.ReadProtection == ReadProtection.ReadOnly)
                        {
                            MessageBox.Show(Messages.CANNOT_DELETE_NODES_FROM_READ_ONLY_LIBRARIES, Messages.ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                        else if (MessageBox.Show(Messages.VIEW_DELETION_CONFIRMATION, Messages.WARNING,
                            MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                        {
                            ViewNodeDeleted(this, new ModelNodeEventArgs<GuidanceExplorer.Model.View>(viewNode));
                        }
                    }
                }
                else if (treeView.SelectedNode is SearchViewNode)
                {
                    if (SearchViewNodeDeleted != null)
                    {
                        SearchViewNode searchViewNode = treeView.SelectedNode as SearchViewNode;
                        if (!searchViewNode.IsEditable)
                        {
                            MessageBox.Show(Messages.CANNOT_DELETE_NODES_FROM_READ_ONLY_LIBRARIES, Messages.ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                        else if (MessageBox.Show(Messages.SEARCH_VIEW_DELETION_CONFIRMATION, Messages.WARNING,
                            MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                        {
                            SearchViewNodeDeleted(this, new ModelNodeEventArgs<SearchView>(searchViewNode));
                        }
                    }
                }
                else if (treeView.SelectedNode is AuthoringToolkitNode)
                {
                    //Do nothing
                }
                else if (treeView.SelectedNode is CreateViewNode)
                {
                    //Do nothing
                }
                else if (treeView.SelectedNode is GuidanceTypeNode)
                {
                    //Do nothing
                }
                else if (treeView.SelectedNode is ChecklistNode)
                {
                    //TODO: delete checklist
                }
            }
            else
            {
                //Unhadled key
            }
        }

        private void treeView_DoubleClick(object sender, EventArgs e)
        {
            TreeView treeview = sender as TreeView;
			TreeNode node = _lastSelectedNode; //treeview.GetNodeAt(((MouseEventArgs)e).X, ((MouseEventArgs)e).Y);

			//_lastClickedNode = node;

            if (node is MyViewsNode)
            {
                if (MyViewsSelected != null)
                {
                    MyViewsSelected(this, new ModelNodeEventArgs<UserViews>(node as MyViewsNode));
                }
            }
            else if (node is LibrariesNode)
            {
                if (LibrariesNodeSelected != null)
                {
                    //LibrariesNodeSelected(this, new ModelNodeEventArgs<LibrariesNode>(node as LibrariesNode));
                    LibrariesNodeSelected(this, null);
                }
            }
            else if (node is LibraryNode)
            {
                if (LibraryNodeSelected != null)
                {
                    LibraryNodeSelected(this, new ModelNodeEventArgs<Library>(node as LibraryNode));
                }
            }
            else if (node is FolderNode)
            {
                if (FolderNodeSelected != null)
                {
                    FolderNodeSelected(this, new ModelNodeEventArgs<Folder>(node as FolderNode));
                }
            }
            else if (node is SearchViewNode)
            {
                if (SearchViewNodeSelected != null)
                {
                    SearchViewNodeSelected(this, new ModelNodeEventArgs<SearchView>(node as SearchViewNode));
                }
            }
            else if (node is ViewNode)
            {
                if (ViewNodeSelected != null)
                {
                    ViewNodeSelected(this, new ModelNodeEventArgs<GuidanceExplorer.Model.View>(node as ViewNode));
                }
            }
            else if (node is AuthoringToolkitNode)
            {
                if (AuthoringToolkitNodeSelected != null)
                {
                    AuthoringToolkitNodeSelected(this, EventArgs.Empty);
                }
            }
            else if (node is CreateViewNode)
            {
                //Do nothing
            }
            else if (node is GuidanceTypeNode)
            {
                if (GuidanceTypeNodeSelected != null)
                {
                    GuidanceTypeNodeSelected(this, new ModelNodeEventArgs<GuidanceType>(node as GuidanceTypeNode));
                }
            }
            else if (node is SolutionNode)
            {
                //Do nothing
            }
            //else if (node is ChecklistsNode)
            //{
            //    if (ChecklistsNodeSelected != null)
            //    {
            //        ChecklistsNodeSelected(this, new ModelNodeEventArgs<GuidanceExplorer.Model.Folder>(node as ChecklistsNode));
            //    }
            //}
            else if (node is ChecklistNode)
            {
                if (ChecklistNodeSelected != null)
                {
                    ChecklistNodeSelected(this, new ModelNodeEventArgs<GuidanceExplorer.Model.Checklist>(node as ChecklistNode));
                }
            }
            else if (node is GuidanceItemNode)
            {
                if (GuidanceItemNodeSelected != null)
                {
                    GuidanceItemNode itemNode = node as GuidanceItemNode;                    
                    GuidanceItemFileReferenceEventArgs eventArgs = new GuidanceItemFileReferenceEventArgs(new GuidanceItemFileReference[] { itemNode.ModelInstance }, ReadProtection.ReadOnly, node.Parent as ViewNode, node.Parent as ChecklistNode);
                    GuidanceItemNodeSelected(this, eventArgs);
                    //GuidanceItemNodeSelected(this, new ModelNodeEventArgs<GuidanceItemFileReference>(node as GuidanceItemNode));
                }

            }
            
            //if (tvwFolders.SelectedNode is GuidanceExplorerTreeNode)
            //{
            //    GuidanceExplorerTreeNode selectedNode = (GuidanceExplorerTreeNode)tvwFolders.SelectedNode;
            //    string filePath = System.IO.Path.GetTempPath() + selectedNode.GuidanceData.Title + ".html";


            //    foreach (Window window in _applicationObject.Windows)
            //        if (window.Caption == filePath)
            //        {
            //            window.SetFocus();
            //            return;
            //        }

            //    GuidanceItem guidanceItem = ModelStorageService.FindItemById(selectedNode.GuidanceData.Id);

            //    if (guidanceItem != null)
            //    {
            //        string cssPath = Path.Combine(CurrentAddInPath, ModelStorageService.TemplateFolder);

            //        GuidanceItemFileReference referencedItem = ModelStorageService.Guidance.GetGuidanceItemFileReference(guidanceItem);


            //        referencedItem.CSSFile = Path.GetFullPath(Path.Combine(CurrentAddInPath, ModelStorageService.TemplateFolder)) + "\\" + ModelStorageService.DefaultCSSFileName;
            //        HtmlRenderService htmlRenderService = new HtmlRenderService();

            //        if (!File.Exists(filePath))
            //            htmlRenderService.RenderGuidanceItemToHtml(referencedItem, new FileInfo(filePath));

            //        Window win = _applicationObject.ItemOperations.Navigate("File://" + filePath, vsNavigateOptions.vsNavigateOptionsNewWindow);
            //    }
            //}
        }

        private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
        {
            if (OpeningContextMenuTreeView != null)
            {
                OpeningContextMenuTreeView(sender, e);
            }
        }


        /// <summary>
        /// Called when a drag operation occurs over the tree view.
        /// </summary>
        private void treeView_DragOver(object sender, DragEventArgs e)
        {
            //Disable by default.
			e.Effect = DragDropEffects.None;

            //Get the node being draged over.
            Point point = treeView.PointToClient(new Point(e.X, e.Y));
            TreeNode hoverNode = treeView.GetNodeAt(point);

            //----- auto-scroll--------
            int delta = treeView.Height - point.Y;
            if ((delta < treeView.Height / 2) && (delta > 0))
            {                
                if (hoverNode.NextVisibleNode != null)
                    hoverNode.NextVisibleNode.EnsureVisible();
            }
            if ((delta > treeView.Height / 2) && (delta < treeView.Height))
            {
                if (hoverNode.PrevVisibleNode != null)
                    hoverNode.PrevVisibleNode.EnsureVisible();
            }
            //----------------------

            //Check if there is a model node.
            IModelItem modelNode = hoverNode as IModelItem;
            if (modelNode != null)
            {
				if (e.Data.GetDataPresent(typeof(ViewNode)))
                {
                    ViewNode draggedViewNode = e.Data.GetData(typeof(ViewNode)) as ViewNode;
                    if (modelNode.CanDrop(draggedViewNode))
                    {
                        e.Effect = e.AllowedEffect;
                    }
                }
                else if (e.Data.GetDataPresent(typeof(FolderNode)))
                {
                    FolderNode draggedFolderNode = e.Data.GetData(typeof(FolderNode)) as FolderNode;
                    if (modelNode.CanDrop(draggedFolderNode))
                    {
                        e.Effect = e.AllowedEffect;
                    }
                }
                else if (e.Data.GetDataPresent(typeof(SearchViewNode)))
                {
                    SearchViewNode draggedSearchNode = e.Data.GetData(typeof(SearchViewNode)) as SearchViewNode;
                    if (modelNode.CanDrop(draggedSearchNode))
                    {
                        e.Effect = e.AllowedEffect;
                    }
                }
                else if (e.Data.GetDataPresent(typeof(GuidanceItem)))
                {
                    GuidanceItem draggedGuidanceItem = e.Data.GetData(typeof(GuidanceItem)) as GuidanceItem;
                    if (modelNode.CanDrop(draggedGuidanceItem))
                    {
                        e.Effect = e.AllowedEffect;
                    }
                }		
				else if (e.Data.GetDataPresent(typeof(GuidanceItemNode)))
				{
					GuidanceItemNode draggedGuidanceItemNode = e.Data.GetData(typeof(GuidanceItemNode)) as GuidanceItemNode;
					if (modelNode.CanDrop(draggedGuidanceItemNode))
					{
						e.Effect = e.AllowedEffect;
					}
				}
                else if (e.Data.GetDataPresent(typeof(GuidanceItemCollection)))
                {
                    GuidanceItemCollection draggedGuidanceItem = e.Data.GetData(typeof(GuidanceItemCollection)) as GuidanceItemCollection;
                    if (modelNode.CanDrop(draggedGuidanceItem))
                    {
                        e.Effect = e.AllowedEffect;
                    }
                }
				else if (e.Data.GetDataPresent(typeof(GuidanceItemFileReference)))
				{
					GuidanceItemFileReference draggedGuidanceItem = e.Data.GetData(typeof(GuidanceItemFileReference)) as GuidanceItemFileReference;
					if (modelNode.CanDrop(draggedGuidanceItem))
					{
						e.Effect = e.AllowedEffect;
					}
				}
				else if (e.Data.GetDataPresent(typeof(ChecklistNode)))
				{
					ChecklistNode draggedGuidanceItem = e.Data.GetData(typeof(ChecklistNode)) as ChecklistNode;
					if (modelNode.CanDrop(draggedGuidanceItem))
					{
						e.Effect = e.AllowedEffect;
					}
				}
				else
				{
					throw new NotSupportedException();
				}
            }
            else
            {
                //Drag over a non-model node.
                MyViewsNode myViewsNode = hoverNode as MyViewsNode;
                if (myViewsNode != null)
                {
                    if (e.Data.GetDataPresent(typeof(ViewNode)))
                    {
                        ViewNode sourceViewNode = e.Data.GetData(typeof(ViewNode)) as ViewNode;
                        if (myViewsNode.CanDrop(sourceViewNode))
                        {
                            e.Effect = e.AllowedEffect;
                        }
                    }
                    else if (e.Data.GetDataPresent(typeof(FolderNode)))
                    {
                        FolderNode sourceFolderNode = e.Data.GetData(typeof(FolderNode)) as FolderNode;
                        if (myViewsNode.CanDrop(sourceFolderNode))
                        {
                            e.Effect = e.AllowedEffect;
                        }
                    }
                    else if (e.Data.GetDataPresent(typeof(SearchViewNode)))
                    {
                        SearchViewNode draggedSearchNode = e.Data.GetData(typeof(SearchViewNode)) as SearchViewNode;
                        if (modelNode.CanDrop(draggedSearchNode))
                        {
                            e.Effect = e.AllowedEffect;
                        }
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }

                }
                else
                {
                    //Unknown non-model node.
                }
            }

            //Set the new and old nodes backcolor
            if ((_oldNode != null) && (_oldNode != hoverNode))
            {
                _oldNode.BackColor = SystemColors.Window;
            }

            if (e.Effect != DragDropEffects.None)
            {
                hoverNode.BackColor = SystemColors.Highlight;
                _oldNode = hoverNode;
            }
			// For fix a bug
			treeView.SelectedNode = null;
			// Redraw selected nodes
			PaintSelectedNodes();
        }

        /// <summary>
        /// Occurs when the node is being drop.
        /// </summary>
        private void treeView_DragDrop(object sender, DragEventArgs e)
        {
            //Reset the node's backcolor
            _oldNode.BackColor = SystemColors.Window;

            //Get the node where the drop operation was detected.
            Point point = treeView.PointToClient(new Point(e.X, e.Y));
            TreeNode dropNode = treeView.GetNodeAt(point);
            IModelItem modelNode = dropNode as IModelItem;

            DragDropOperation op = new DragDropOperation();
			op.From = _lastSelectedNode;

            if (modelNode != null)
            {
                ViewNode dropViewNode = dropNode as ViewNode;
                FolderNode dropFolderNode = dropNode as FolderNode;

                MyViewsNode dropMyViewsNode = dropNode as MyViewsNode;
                LibraryNode dropLibraryNode = dropNode as LibraryNode;
                ChecklistNode dropChecklistNode = dropNode as ChecklistNode;
				SolutionNode dropSolutionNode = dropNode as SolutionNode;
				SearchViewNode dropSearchViewNode = dropNode as SearchViewNode;

                //View node is being dropped
                if (e.Data.GetDataPresent(typeof(ViewNode)))
                {
                    ViewNode dragViewNode = e.Data.GetData(typeof(ViewNode)) as ViewNode;
                    if (modelNode.CanDrop(dragViewNode))
                    {
                        #region Drop View 
                        
                        //view dropped to a folder
                        if (dropFolderNode != null)
                        {
                            if (DropViewToFolder != null)
                            {
                                op.Item = dragViewNode;
                                op.PreviousPosition = dragViewNode.Index;
                                op.From = dragViewNode.Parent;
                                op.To = dropFolderNode;
                                _operations.Push(op);

                                DropOperationEventArgs<GuidanceExplorer.Model.View, Folder> eventArgs =
                                    new DropOperationEventArgs<GuidanceExplorer.Model.View, Folder>(dragViewNode, dropFolderNode);
                                DropViewToFolder(this, eventArgs);
                            }
                        }
                        //view dropped to MyViews node
                        else if (dropMyViewsNode != null)
                        {
                            if (DropViewToUserViews != null)
                            {
                                op.Item = dragViewNode;
                                op.PreviousPosition = dragViewNode.Index;
                                op.From = dragViewNode.Parent;
                                op.To = dropMyViewsNode;
                                _operations.Push(op);

                                DropOperationEventArgs<GuidanceExplorer.Model.View, UserViews> eventArgs =
                                    new DropOperationEventArgs<GuidanceExplorer.Model.View, UserViews>(dragViewNode, dropMyViewsNode);
                                DropViewToUserViews(this, eventArgs);
                            }
                        }
                        //view dropped to libraries node
                        else if (dropLibraryNode != null)
                        {
                            if (DropViewToLibrary != null)
                            {
                                op.Item = dragViewNode;
                                op.PreviousPosition = dragViewNode.Index;
                                op.From = dragViewNode.Parent;
                                op.To = dropLibraryNode;
                                _operations.Push(op);

                                DropOperationEventArgs<GuidanceExplorer.Model.View, Library> eventArgs =
                                    new DropOperationEventArgs<GuidanceExplorer.Model.View, Library>(dragViewNode, dropLibraryNode);
                                DropViewToLibrary(this, eventArgs);
                            }
                        }
                        //view dropped to solution node
						else if (dropSolutionNode != null)
						{
							if (DropViewToSolutionNode != null)
							{
								op.Item = dragViewNode;
								op.PreviousPosition = dragViewNode.Index;
								op.From = dragViewNode.Parent;
								op.To = dropFolderNode;
								_operations.Push(op);

								DropOperationEventArgs<GuidanceExplorer.Model.View, SolutionViews> eventArgs =
									new DropOperationEventArgs<GuidanceExplorer.Model.View, SolutionViews>(dragViewNode, dropSolutionNode);
								DropViewToSolutionNode(this, eventArgs);

							}
						}
						//view dropped to ckecklist node
						else if (dropChecklistNode != null)
						{
							if (DropViewToChecklist != null)
							{
								op.Item = dragViewNode;
								op.PreviousPosition = dragViewNode.Index;
								op.From = dragViewNode.Parent;
								op.To = dropChecklistNode;
								_operations.Push(op);

								DropOperationEventArgs<GuidanceExplorer.Model.View, Checklist> eventArgs =
									new DropOperationEventArgs<GuidanceExplorer.Model.View, Checklist>(dragViewNode, dropChecklistNode);
								DropViewToChecklist(this, eventArgs);
							}
						}
						//view dropped to view
						else if (dropViewNode != null)
						{
							if (DropViewToView != null)
							{
								op.Item = dragViewNode;
								op.PreviousPosition = dragViewNode.Index;
								op.From = dragViewNode.Parent;
								op.To = dropViewNode;
								_operations.Push(op);

								DropOperationEventArgs<GuidanceExplorer.Model.View, GuidanceExplorer.Model.View> eventArgs =
									new DropOperationEventArgs<GuidanceExplorer.Model.View, GuidanceExplorer.Model.View>(dragViewNode, dropViewNode);
								DropViewToView(this, eventArgs);
							}
						}
						
                        return;

                        #endregion
                    }
                }
				else if (e.Data.GetDataPresent(typeof(ChecklistNode)))
				{
					ChecklistNode dragChecklistNode = e.Data.GetData(typeof(ChecklistNode)) as ChecklistNode;
					if ( modelNode.CanDrop(dragChecklistNode) )
					{
						#region Drop CheckList
						if (dropFolderNode != null)
						{
							if (DropCheckListToFolder != null)
							{
								op.Item = dragChecklistNode;
								op.PreviousPosition = dragChecklistNode.Index;
								op.From = dragChecklistNode.Parent;
								op.To = dropFolderNode;
								_operations.Push(op);

								DropOperationEventArgs<GuidanceExplorer.Model.Checklist, Folder> eventArgs =
									new DropOperationEventArgs<GuidanceExplorer.Model.Checklist, Folder>(dragChecklistNode, dropFolderNode);
								DropCheckListToFolder(this, eventArgs);
							}
						}
						else if (dropSolutionNode != null)
						{
							if (DropCheckListToSolutionNode != null)
							{
								op.Item = dragChecklistNode;
								op.PreviousPosition = dragChecklistNode.Index;
								op.From = dragChecklistNode.Parent;
								op.To = dropFolderNode;
								_operations.Push(op);

								DropOperationEventArgs<Checklist, SolutionViews> eventArgs =
									new DropOperationEventArgs<Checklist, SolutionViews>(dragChecklistNode, dropSolutionNode);
								DropCheckListToSolutionNode(this, eventArgs);

							}
						}
										
						return;
						#endregion

					}
				}
				else if (e.Data.GetDataPresent(typeof(SearchViewNode)))
				{
					SearchViewNode dragSearchNode = e.Data.GetData(typeof(SearchViewNode)) as SearchViewNode;
					if (modelNode.CanDrop(dragSearchNode))
					{
						#region Drop Search View
						if (dropFolderNode != null)
						{
							if (DropSearchViewToFolder != null)
							{
								op.Item = dragSearchNode;
								op.PreviousPosition = dragSearchNode.Index;
								op.From = dragSearchNode.Parent;
								op.To = dropFolderNode;
								_operations.Push(op);

								DropOperationEventArgs<SearchView, Folder> eventArgs =
									new DropOperationEventArgs<SearchView, Folder>(dragSearchNode, dropFolderNode);
								DropSearchViewToFolder(this, eventArgs);
							}
						}
						else if (dropMyViewsNode != null)
						{
							if (DropSearchViewToUserViews != null)
							{
								op.Item = dragSearchNode;
								op.PreviousPosition = dragSearchNode.Index;
								op.From = dragSearchNode.Parent;
								op.To = dropMyViewsNode;
								_operations.Push(op);

								DropOperationEventArgs<SearchView, UserViews> eventArgs =
									new DropOperationEventArgs<SearchView, UserViews>(dragSearchNode, dropMyViewsNode);
								DropSearchViewToUserViews(this, eventArgs);
							}
						}
						else if (dropLibraryNode != null)
						{
							if (DropSearchViewToLibrary != null)
							{
								op.Item = dragSearchNode;
								op.PreviousPosition = dragSearchNode.Index;
								op.From = dragSearchNode.Parent;
								op.To = dropLibraryNode;
								_operations.Push(op);

								DropOperationEventArgs<SearchView, Library> eventArgs =
									new DropOperationEventArgs<SearchView, Library>(dragSearchNode, dropLibraryNode);
								DropSearchViewToLibrary(this, eventArgs);
							}
						}
						else if (dropSearchViewNode != null)
						{
							if (DropSearchViewToFolder != null)
							{
								op.Item = dragSearchNode;
								op.PreviousPosition = dragSearchNode.Index;
								op.From = dragSearchNode.Parent;
								op.To = dropLibraryNode;
								_operations.Push(op);

								DropOperationEventArgs<SearchView, Folder> eventArgs =
									new DropOperationEventArgs<SearchView, Folder>(dragSearchNode, dropFolderNode);
								DropSearchViewToFolder(this, eventArgs);

							}
						}
						else if (dropChecklistNode != null)
						{
							if (DropSearchViewToCheckList != null)
							{
								op.Item = dragSearchNode;
								op.PreviousPosition = dragSearchNode.Index;
								op.From = dragSearchNode.Parent;
								op.To = dropLibraryNode;
								_operations.Push(op);

								Cursor = System.Windows.Forms.Cursors.WaitCursor;
								DropOperationEventArgs<SearchView, Checklist> eventArgs =
									new DropOperationEventArgs<SearchView, Checklist>(dragSearchNode, dropChecklistNode);
								DropSearchViewToCheckList(this, eventArgs);
								Cursor = System.Windows.Forms.Cursors.Arrow;
							}
						}
						else if (dropViewNode != null)
						{
							if (DropSearchViewToView != null)
							{
								op.Item = dragSearchNode;
								op.PreviousPosition = dragSearchNode.Index;
								op.From = dragSearchNode.Parent;
								op.To = dropViewNode;
								_operations.Push(op);

								DropOperationEventArgs<SearchView, GuidanceExplorer.Model.View> eventArgs =
									new DropOperationEventArgs<SearchView, GuidanceExplorer.Model.View>(dragSearchNode, dropViewNode);
								DropSearchViewToView(this, eventArgs);
							}
						}
						else
						{
							throw new NotSupportedException();
						}
						return;
						#endregion
					}
				}
				else if (e.Data.GetDataPresent(typeof(FolderNode)))
				{
					FolderNode dragFolderNode = e.Data.GetData(typeof(FolderNode)) as FolderNode;
					if (modelNode.CanDrop(dragFolderNode))
					{
						#region Drop Folder
						if (dropFolderNode != null)
						{
							if (DropFolderToFolder != null)
							{
								op.Item = dragFolderNode;
								op.PreviousPosition = dragFolderNode.Index;
								op.From = dragFolderNode.Parent;
								op.To = dropFolderNode;
								_operations.Push(op);

								DropOperationEventArgs<Folder, Folder> eventArgs =
									new DropOperationEventArgs<Folder, Folder>(dragFolderNode, dropFolderNode);
								DropFolderToFolder(this, eventArgs);
							}
						}
						else if (dropSolutionNode != null)
						{
							if (DropFolderToSolutionNode != null)
							{
								op.Item = dragFolderNode;
								op.PreviousPosition = dragFolderNode.Index;
								op.From = dragFolderNode.Parent;
								op.To = dropSolutionNode;
								_operations.Push(op);

								Cursor = System.Windows.Forms.Cursors.WaitCursor;
								DropOperationEventArgs<Folder, SolutionViews> eventArgs =
									new DropOperationEventArgs<Folder, SolutionViews>(dragFolderNode, dropSolutionNode);
								DropFolderToSolutionNode(this, eventArgs);
								Cursor = System.Windows.Forms.Cursors.Arrow;

							}

						}
						else if (dropLibraryNode != null)
						{
							if (DropFolderToLibrary != null)
							{
								op.Item = dragFolderNode;
								op.PreviousPosition = dragFolderNode.Index;
								op.From = dragFolderNode.Parent;
								op.To = dropLibraryNode;
								_operations.Push(op);

								DropOperationEventArgs<Folder, Library> eventArgs =
									new DropOperationEventArgs<Folder, Library>(dragFolderNode, dropLibraryNode);
								DropFolderToLibrary(this, eventArgs);
							}
						}
						else if (dropMyViewsNode != null)
						{
							if (DropFolderToUserViews != null)
							{
								op.Item = dragFolderNode;
								op.PreviousPosition = dragFolderNode.Index;
								op.From = dragFolderNode.Parent;
								op.To = dropMyViewsNode;
								_operations.Push(op);

								DropOperationEventArgs<Folder, UserViews> eventArgs =
									new DropOperationEventArgs<Folder, UserViews>(dragFolderNode, dropMyViewsNode);
								DropFolderToUserViews(this, eventArgs);
							}
						}
						else if (dropChecklistNode != null)
						{
							if (DropFolderToCheckList != null)
							{
								op.Item = dragFolderNode;
								op.PreviousPosition = dragFolderNode.Index;
								op.From = dragFolderNode.Parent;
								op.To = dropChecklistNode;
								_operations.Push(op);


								Cursor = System.Windows.Forms.Cursors.WaitCursor;
								DropOperationEventArgs<Folder, Checklist> eventArgs =
									new DropOperationEventArgs<Folder, Checklist>(dragFolderNode, dropChecklistNode);
								DropFolderToCheckList(this, eventArgs);
								Cursor = System.Windows.Forms.Cursors.Arrow;
							}
						}
						else if (dropViewNode != null)
						{
							if (DropFolderToView != null)
							{
								op.Item = dragFolderNode;
								op.PreviousPosition = dragFolderNode.Index;
								op.From = dragFolderNode.Parent;
								op.To = dropViewNode;
								_operations.Push(op);


								Cursor = System.Windows.Forms.Cursors.WaitCursor;
								DropOperationEventArgs<Folder, GuidanceExplorer.Model.View> eventArgs =
									new DropOperationEventArgs<Folder, GuidanceExplorer.Model.View>(dragFolderNode, dropViewNode);
								DropFolderToView(this, eventArgs);
								Cursor = System.Windows.Forms.Cursors.Arrow;

							}
						}
						else
						{
							throw new NotSupportedException();
						}
						return;
						#endregion
					}
				}
				else if (e.Data.GetDataPresent(typeof(GuidanceItem)) ||
					e.Data.GetDataPresent(typeof(GuidanceItemCollection)) ||
					e.Data.GetDataPresent(typeof(GuidanceItemFileReference)) || e.Data.GetDataPresent(typeof(GuidanceItemNode)))
				{
					// Check if the item was dragged from the tree of from outside
					GuidanceItemCollection draggedGuidanceItemCollection = null;
					if (_mouseDown)
					{
						// It was dragged from the tree, use selected nodes
						draggedGuidanceItemCollection = GuidanceItemCollection.New();
						foreach (TreeNode node in _selectedNodes)
						{
							draggedGuidanceItemCollection.Add(((GuidanceItemNode)node).ModelInstance.Id, ((GuidanceItemNode)node).ModelInstance);
						}

						// Clear selection
						RemovePaintFromNodes();
						_selectedNodes.Clear();
					}
					else
					{
						// It wasn't dragged from the tree, use the event data
						draggedGuidanceItemCollection = e.Data.GetData(typeof(GuidanceItemCollection)) as GuidanceItemCollection;
						if (draggedGuidanceItemCollection == null)
						{
							// There was no item collection, so create one with the dragged item
							GuidanceItem draggedGuidanceItem = e.Data.GetData(typeof(GuidanceItem)) as GuidanceItem;
							GuidanceItemFileReference draggedGuidanceItemFileReference = e.Data.GetData(typeof(GuidanceItemFileReference)) as GuidanceItemFileReference;

							if (draggedGuidanceItemFileReference == null && draggedGuidanceItem != null)
							{
								draggedGuidanceItemFileReference = draggedGuidanceItem.ReferencedItem;
								if (draggedGuidanceItemFileReference == null)
								{
									draggedGuidanceItemFileReference = (GuidanceItemFileReference)draggedGuidanceItem;
								}
							}

							draggedGuidanceItemCollection = GuidanceItemCollection.New();
							draggedGuidanceItemCollection.Add(draggedGuidanceItemFileReference.Id, draggedGuidanceItemFileReference);
						}
					}

					// Make the drop, if possible
					if (modelNode.CanDrop(draggedGuidanceItemCollection))
					{
						#region Drop Guidance Item Collection

						// Is dropped to a view of checklist?
						if (dropViewNode != null)
						{
							// Raise the event
							ItemDropOperationEventArgs<GuidanceItemFileReference, GuidanceExplorer.Model.View> eventArgs =
								new ItemDropOperationEventArgs<GuidanceItemFileReference, GuidanceExplorer.Model.View>(
									draggedGuidanceItemCollection.Values.Select(g => (GuidanceItemFileReference)g).ToList(),
									dropViewNode);

							DropItemToView(this, eventArgs);
						}
						else if (dropChecklistNode != null)
						{
							// Raise the event
							ItemDropOperationEventArgs<GuidanceItemFileReference, Checklist> eventArgs =
								new ItemDropOperationEventArgs<GuidanceItemFileReference, Checklist>(
									draggedGuidanceItemCollection.Values.Select(g => (GuidanceItemFileReference)g).ToList(),
									dropChecklistNode);

							DropItemToChecklist(this, eventArgs);
						}
						#endregion
					}
				}
            }

			// Redraw selected nodes
			PaintSelectedNodes();
        }

        //public static void AddGuidanceToTreeNode(TreeNode dropViewNode, GuidanceItemFileReference draggedGuidanceItemFileReference)
        //{
        //    GuidanceItemNode itemNode = GuidanceItemNode.New();
        //    itemNode.Text = draggedGuidanceItemFileReference.Title;
        //    itemNode.ModelInstance = draggedGuidanceItemFileReference;
        //    dropViewNode.Nodes.Add(itemNode);
        //}

        private void treeView_Click(object sender, EventArgs e)
        {
			ArrayList list = new ArrayList();
			foreach (TreeNode node in _selectedNodes)
            {            
			    // Check which tree node type was selected
                SolutionNode solutionNode = node as SolutionNode;
                MyViewsNode myViewsNode = node as MyViewsNode;
                //LibrariesNode librariesNode = node as LibrariesNode;
                LibraryNode libraryNode = node as LibraryNode;
                FolderNode folderNode = node as FolderNode;
                ViewNode viewNode = node as ViewNode;
                SearchViewNode searchViewNode = node as SearchViewNode;
                GuidanceTypeNode typeNode = node as GuidanceTypeNode;
			    GuidanceItemNode itemNode = node as GuidanceItemNode;
                ChecklistNode checklistNode = node as ChecklistNode;
                if (solutionNode != null)
                {
                    list.Add(solutionNode.ModelInstance);
                }
                else if (myViewsNode != null)
                {
                    list.Add(myViewsNode.ModelInstance);
                }
                //else if (librariesNode != null)
                //{
                //    list.Add(librariesNode.ModelInstance);
                //}
                else if (libraryNode != null)
                {
                    list.Add(libraryNode.ModelInstance);
                }
			    else if (folderNode != null)
			    {   
			        list.Add(folderNode.ModelInstance);
	            }
                else if (viewNode != null)
                {
                    list.Add(viewNode.ModelInstance);
                }
                else if (searchViewNode != null)
                {
                    list.Add(searchViewNode.ModelInstance);
                }
                else if (typeNode != null)
                {
                    list.Add(typeNode.ModelInstance);
                }
                else if (itemNode != null)
                {
                    list.Add(itemNode.ModelInstance);
                }
                else if (checklistNode != null)
                {
                    list.Add(checklistNode.ModelInstance);
                }
            }
			treeView.SelectedNode = null;
			tool.OnSelectionChange(list);
        }

        private void treeView_ItemDrag(object sender, ItemDragEventArgs e)
        {
			if (e.Item is GuidanceItem)
			{
				GuidanceItem itemNode = e.Item as GuidanceItem;
				treeView.DoDragDrop(itemNode, DragDropEffects.Link);
			}
			if (e.Item is GuidanceItemCollection)
			{
				GuidanceItemCollection itemNodeCollection = e.Item as GuidanceItemCollection;
				treeView.DoDragDrop(itemNodeCollection, DragDropEffects.Link);
			}
			if (e.Item is GuidanceItemNode)
            {
				GuidanceItemNode guidanceItemNode = e.Item as GuidanceItemNode;
				treeView.DoDragDrop(guidanceItemNode, DragDropEffects.Link);
            }
			else if (e.Item is ViewNode)
			{
				ViewNode viewNode = e.Item as ViewNode;
				treeView.DoDragDrop(viewNode, DragDropEffects.Move);
			}
			else if (e.Item is FolderNode)
			{
				FolderNode folderNode = e.Item as FolderNode;
				treeView.DoDragDrop(folderNode, DragDropEffects.Move);
			}
			else if (e.Item is ChecklistNode)
			{
				ChecklistNode checkListNode = e.Item as ChecklistNode;
				treeView.DoDragDrop(checkListNode, DragDropEffects.Move);
			}
			else if (e.Item is SearchViewNode)
			{
				SearchViewNode searchViewNode = e.Item as SearchViewNode;
				treeView.DoDragDrop(searchViewNode, DragDropEffects.Move);
			}
			
		}

        private void treeView_MouseDown(object sender, MouseEventArgs e)
        {
			TreeNode node = treeView.GetNodeAt(e.X, e.Y);
            if (node == null && treeView.SelectedNode != null)
            {
                if (treeView.SelectedNode.IsEditing)
                {
                    afterEditMessageShown = true;
                }
            }

			// Register mouse was clicked at the tree view
			_mouseDown = true;

			// Process selection
            if (node != null)
            {
                ProcessSelection(node, e);
            }
        }

		//private void treeView_MouseMove(object sender, MouseEventArgs e)
		//{
		//    //base.OnMouseMove(e);

		//    // Filter out false move events and start drag&drop operation
		//    if (e.Location != ltmbpoint && lmbdown && dragRow != null)
		//    {
		//        // Send the selected DataGridViewRow
		//        if (dataGridView.SelectedRows.Count == 1)
		//        {
		//            GuidanceItem item = dataGridView.SelectedRows[0].Tag as GuidanceItem;
		//            dataGridView.DoDragDrop(item, DragDropEffects.Link);
		//        }
		//        else if (dataGridView.SelectedRows.Count > 1)
		//        {
		//            GuidanceItemCollection guidanceItems = GuidanceItemCollection.New();
		//            foreach (DataGridViewRow row in dataGridView.SelectedRows)
		//            {
		//                GuidanceItem guidanceItem = row.Tag as GuidanceItem;
		//                if (guidanceItem != null)
		//                {
		//                    guidanceItems.Add(guidanceItem.Id, guidanceItem);
		//                }
		//            }
		//            dataGridView.DoDragDrop(guidanceItems, DragDropEffects.Link);
		//        }
		//        lmbdown = false;
		//    }
		//}

		private void treeView_MouseUp(object sender, MouseEventArgs e)
		{
			// Register mouse is clicked no more from the tree view
			_mouseDown = false;
            if (_onlyClick)
            {
                TreeNode node = treeView.GetNodeAt(e.X, e.Y);

                RemovePaintFromNodes();
                _selectedNodes.Clear();
                _selectedNodes.Add(node);
                PaintSelectedNode(node);

                // Update the last selected node
                _lastSelectedNode = node;

                _onlyClick = false;
            }

		}

		/// <summary>
		/// Adds the Solution node with the specified name and populates it with the projects of the solution.
		/// </summary>
        //public void CreateSolutionNode(string solutionName)
        //{
        //    // Create solution node
        //    SolutionNode solutionNode = SolutionNode.New(solutionName);
        //    //solutionNode.ModelInstance = ModelService.Guidance.ProjectFolders;
        //    treeView.Nodes.Insert(0, solutionNode);

        //    //Populate My Projects node
        //    WinFormsRenderService winFormsRenderService = new WinFormsRenderService();
        //    //winFormsRenderService.RenderProjectsToMyProjects(treeView, ModelService.Guidance.ProjectFolders, solutionNode, ModelService.Guidance);

        //    // Show the solution items
        //    solutionNode.Expand();
        //}

		/// <summary>
		/// Removes the solution node from the tree
		/// </summary>
		public void DeleteSolutionNode()
		{
			// Maybe this is not the best way to do it...
			treeView.Nodes.RemoveAt(0);
		}


        /// <summary>
        /// Return the node name when it is added to the Tree View
        /// </summary>
        /// <param name="parent">Parent node</param>
        /// <param name="name">New node name</param>
        /// <returns></returns>
        public string GetNewLibraryName(LibraryCollection libraryCollection, TreeNode parent, string name)
        {
            string folderName = name;
            int foldersCount = 0;

            if (NodeExists(parent.Nodes, folderName))
            {
                foldersCount = GetNodesCount(parent.Nodes, folderName);

                while (NodeExists(parent.Nodes, folderName))
                {
                    folderName = name + foldersCount.ToString();
                    foldersCount++;
                }
            }

            while (libraryCollection.ContainsKey(folderName))
            {
                folderName = name + foldersCount.ToString();
                foldersCount++;
            }

            return folderName;
        }


        /// <summary>
        /// Returns true if there's a node with the provided name
        /// </summary>
        /// <param name="nodes"></param>
        /// <param name="folderName"></param>
        /// <returns></returns>
        private bool NodeExists(TreeNodeCollection nodes, string nodeName)
        {
            foreach (TreeNode node in nodes)
            {
                if (string.Compare(node.Text, nodeName) == 0)
                {
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Returns how many nodes with the provided name are in the node collection
        /// </summary>
        /// <param name="nodes"></param>
        /// <param name="nodeName"></param>
        /// <returns></returns>
        private int GetNodesCount(TreeNodeCollection nodes, string nodeName)
        {
            int count = 0;
            Regex regex = new Regex("(" + nodeName + "([0-9]){0,})", RegexOptions.IgnoreCase);

            foreach (TreeNode t in nodes)
            {
                if (t.Text.StartsWith(nodeName, StringComparison.CurrentCultureIgnoreCase) &&
                    regex.Match(t.Text).Success)
                {
                    count++;
                }
            }
            return count;
        }


		#region MultiSelect TreeNode


		protected List<TreeNode> _selectedNodes = new List<TreeNode>();
		protected TreeNode _lastNode, _firstNode;

		public List<TreeNode> SelectedNodes
		{
			get
			{
                if (_selectedNodes == null)
                    _selectedNodes = new List<TreeNode>();

				return _selectedNodes;
			}
			set
			{
				TreeView.SelectedNode = null;
				RemovePaintFromNodes();
				_selectedNodes.Clear();
				_selectedNodes = value;
				PaintSelectedNodes();
			}
		}

        protected void ProcessSelection(TreeNode node, MouseEventArgs e)
		{
			bool bControl = (ModifierKeys == Keys.Control);
			bool bShift = (ModifierKeys == Keys.Shift);

			// Allow multi selection over guidance item nodes only
			if (bControl && node is GuidanceItemNode)
            {
                #region Control Multiselect 
                // Check if the node was or wasn't already selected
				if (_selectedNodes.Contains(node))
				{
					// The node is selected no more
					_selectedNodes.Remove(node);
					RemovePaintFromNode(node);

					// If it is the selected node of the tree view, select another one of the multi selected's
					if (treeView.SelectedNode == node)
					{
						// If it was the only one selected, select none
						if (_selectedNodes.Count == 0)
						{
							treeView.SelectedNode = null;
						}
						else
						{
							treeView.SelectedNode = _selectedNodes[0];
						}
					}
				}
				else
				{
					// Check if there was only 1 node selected before, it might not be a guidance item.
					if (_selectedNodes.Count == 1  &&  !(_selectedNodes[0] is GuidanceItemNode))
					{
						RemovePaintFromNode(_selectedNodes[0]);
						_selectedNodes.Clear();
					}

					// The node is now selected
					_selectedNodes.Add(node);
					PaintSelectedNode(node);

					// Update the last selected node
					_lastSelectedNode = node;
                }
                #endregion
            }
            else if (bShift && node is GuidanceItemNode)
            {
                #region shift multiselection
                // Shift+Click selects nodes between the selected node and here.
                TreeNode ndStart = node;
                TreeNode ndEnd = _lastSelectedNode;

                if (ndStart.Parent == ndEnd.Parent)
                {
                    RemovePaintFromNodes();
                    _selectedNodes.Clear();
                    _selectedNodes.Add(ndStart);

                    // Selected node and clicked node have same parent, easy case.
                    if (ndStart.Index < ndEnd.Index)
                    {

                        // If the selected node is beneath 
                        // the clicked node walk down
                        // selecting each Visible node until we reach the end.
                        while (ndStart != ndEnd)
                        {
                            ndStart = ndStart.NextVisibleNode;
                            if (ndStart == null) break;
                            _selectedNodes.Add(ndStart);
                        }
                    }
                    else if (ndStart.Index == ndEnd.Index)
                    {
                        // Do nothing
                    }
                    else
                    {
                        // If the selected node is above the clicked node walk up
                        // selecting each Visible node until we reach the end.
                        while (ndStart != ndEnd)
                        {
                            ndStart = ndStart.PrevVisibleNode;
                            if (ndStart == null) break;
                            _selectedNodes.Add(ndStart);
                        }
                    }
                    PaintSelectedNodes();
                }
                #endregion
            }
            else if (_mouseDown && _selectedNodes.Contains(node))
            {
                if (e.Button == MouseButtons.Left)
                {
                    _onlyClick = true;
                }
            }
            else
            {
                // Allow only one node selected at a time
                RemovePaintFromNodes();
                _selectedNodes.Clear();
                _selectedNodes.Add(node);
                PaintSelectedNode(node);

                // Update the last selected node
                _lastSelectedNode = node;
            }
		}

        protected void treeView_OnBeforeSelect(object sender, TreeViewCancelEventArgs e)
        {

            // I want to ensure tree view isn't selecting a node his way
            // TODO: It keeps tring to have SelectedNode != null

            treeView.SelectedNode = null;
            e.Cancel = true;
        }
		
		protected bool IsParent(TreeNode parentNode, TreeNode childNode)
		{
			if (parentNode == childNode)
				return true;

			TreeNode n = childNode;
			bool bFound = false;
			while (!bFound && n!=null)
			{
				n = n.Parent;
				bFound = (n == parentNode);
			}
			return bFound;
		}
		protected void PaintSelectedNodes()
		{
            if (_selectedNodes != null)
            {
                foreach (TreeNode n in _selectedNodes)
                {
                    if (n != null)
                    {
                        n.BackColor = SystemColors.Highlight;
                        n.ForeColor = SystemColors.HighlightText;
                    }
                }
            }
		}
		protected void PaintSelectedNode(TreeNode node)
		{
			node.BackColor = SystemColors.Highlight;
			node.ForeColor = SystemColors.HighlightText;
		}
		protected void RemovePaintFromNodes()
		{
			if (_selectedNodes.Count == 0)
				return;

			Color back = treeView.BackColor;
			Color fore = treeView.ForeColor;

			foreach (TreeNode n in _selectedNodes)
			{
                if (n != null)
                {
                    n.BackColor = back;
                    n.ForeColor = fore;
                }
			}
		}
		protected void RemovePaintFromNode(TreeNode node)
		{
            if (node != null)
            {
                node.BackColor = treeView.BackColor;
                node.ForeColor = treeView.ForeColor;
            }
		}

		#endregion

        /// <summary>
        /// Populate search views on demand because they take too long to render in tree view
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void treeView_AfterExpand(object sender, TreeViewEventArgs e)
        {
            if (e.Node is FolderNode || e.Node is SolutionNode || e.Node is MyViewsNode || e.Node is LibraryNode)
            {
                WinFormsRenderService serv = new WinFormsRenderService();
                foreach (TreeNode node in e.Node.Nodes)
                {
                    if (node is SearchViewNode && node.Nodes.Count == 0)
                    {
                        SearchViewNode searchViewNode = node as SearchViewNode;
                        serv.RenderItemsToViewNode(ModelService.Guidance, searchViewNode.ModelInstance, searchViewNode);
                    } 
                }
            }
        }
	}

}







